package com.storyroad.utils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import com.storyroad.responseClasses.StoryLinkObject;

/**
 * 
 * This class is used to obtain all story fragments in a story. Fragments can be linked together to form a story.
 * Linking stories to each other creates a parent-child relationship between the fragments. Hence a story can be
 * viewed as a tree where nodes represent the story fragments and edges represent a link between them. This class
 * and its methods are used to find all fragments in a tree given the ID of a story fragment. After getting the ID
 * of a story fragment, the tree is traversed both in upward and downward direction to get all story fragments.
 */
public class GetStoryLinks {

	ArrayList<StoryLinkObject> resultList;
	Connection conn;
	PreparedStatement stmt;

	/**
	 * Finds the story fragments that are linked to each other and form a tree together.
	 * @param storyId ID of the story fragment. The tree that this fragment belongs to will be traversed.
	 * @return a list of {@link com.storyroad.responseClasses.StoryLinkObject} instances which contain all story fragments
	 * in the story tree
	 */
	public ArrayList<StoryLinkObject> getStoryLink(int storyId) {
		conn = new DBConnection().connect();
		stmt = null;
		resultList = new ArrayList<StoryLinkObject>();
		startProcess(storyId);
		return resultList;
	}

	/**
	 * Begins obtaining the tree. This method first calls a function to find all parents of the given story fragment and then
	 * it calls another function to find the children of this story fragment.
	 * @param storyId storyId ID of the story fragment
	 */
	private void startProcess(int storyId) {

		StoryLinkObject storyLinkObject = new StoryLinkObject(storyId);
		resultList.add(storyLinkObject);
		findParent(storyLinkObject);
		findChildren(storyLinkObject);
	}

	/**
	 * Starting from the given story fragment, the tree is traversed upwards to collect all ancestors of this story fragment.
	 * @param storyLinkObject an instance of {@link com.storyroad.responseClasses.StoryLinkObject} which stores the story
	 * fragment whose parent is currently looked for
	 */
	private void findParent(StoryLinkObject storyLinkObject) {
		ResultSet rs;
		int newStoryId = 0;
		StoryLinkObject storyLinkObject2 = new StoryLinkObject(0);
		try {
			stmt = conn.prepareStatement("SELECT * FROM "
					+ TableNames.STORIES_TABLE + " WHERE s_id = ?");
			stmt.setInt(1, storyLinkObject.getStory_id());
			rs = stmt.executeQuery();
			if (rs.next()) {
				newStoryId = rs.getInt("parent");
				storyLinkObject2 = new StoryLinkObject(newStoryId);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		if (resultList.contains(storyLinkObject2)
				|| storyLinkObject2.getStory_id() == 0) {
			return;
		} else {
			storyLinkObject.setParent_id(newStoryId);
			resultList.add(0, storyLinkObject2);
			findParent(storyLinkObject2);
			findChildren(storyLinkObject2);
		}
	}

	/**
	 * Starting from the given story fragment, the tree is traversed downwards to collect all children of this story fragment.
	 * @param storyLinkObject an instance of {@link com.storyroad.responseClasses.StoryLinkObject} which stores the story
	 * fragment whose children are currently looked for
	 */
	private void findChildren(StoryLinkObject storyLinkObject) {
		ResultSet rs;
		ArrayList<StoryLinkObject> children = new ArrayList<StoryLinkObject>();
		try {
			stmt = conn.prepareStatement("SELECT * FROM "
					+ TableNames.STORIES_TABLE + " WHERE parent = ?");
			stmt.setInt(1, storyLinkObject.getStory_id());
			rs = stmt.executeQuery();
			while (rs.next()) {
				StoryLinkObject storyLinkObject2 = new StoryLinkObject(
						rs.getInt("s_id"));
				children.add(storyLinkObject2);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (children.size() == 0) {
			return;
		} else {
			for (int i = 0; i < children.size(); i++) {
				if (resultList.contains(children.get(i))) {
					continue;
				}
				children.get(i).setParent_id(storyLinkObject.getStory_id());
				resultList.add(children.get(i));
				findChildren(children.get(i));
			}
		}
	}
}
